package tools

import (
	"encoding/json"
	"fmt"
	"github.com/BurntSushi/toml"
	"log"
	"maps"
	"math/rand"
	"os"
	"path/filepath"
	"slices"
	"sort"
	"strconv"
	"strings"
	"time"
	"vector/tools/middle"
)

const configDir = "config"

var Config = &Configure{
	Account:  new(account),
	Excel:    new(excel),
	Vector:   new(vector),
	SseChat:  new(requestConfig),
	Dispatch: new(requestConfig),
	Agent:    map[string]agent{},
	FAQ:      new(FaQConfig),
	AiCanvas: new(aiCanvasConfig),
}

type Configure struct {
	baseConfig
	Account  *account
	Excel    *excel
	Vector   *vector
	SseChat  *requestConfig
	Dispatch *requestConfig
	Agent    map[string]agent
	FAQ      *FaQConfig
	AiCanvas *aiCanvasConfig
}

type baseConfig struct {
	BaseSleep     time.Duration
	DataSource    string
	InterceptNum  int
	IsSimplePrint bool
	RunMode       string
	Sheet         string
	ThreadNum     int
}

func (c *Configure) SetArgs(sleep time.Duration, dataSource string, isIntercept int,
	isSimplePrint bool, runMode string, sheet string, threadNum int) {
	c.BaseSleep = sleep
	c.DataSource = dataSource
	c.InterceptNum = isIntercept
	c.IsSimplePrint = isSimplePrint
	c.RunMode = runMode
	c.Sheet = sheet
	c.ThreadNum = threadNum

	// 增加文件存在性校验
	if _, err := os.Stat(c.DataSource); os.IsNotExist(err) {
		log.Fatalf("数据源文件 %s 不存在", c.DataSource)
	}

	c.ReadConfig()
}

// ReadConfig 初始化读取配置文件
func (c *Configure) ReadConfig() {

	var configFiles = map[string]any{
		"agent":    &c.Agent,
		"excel":    c.Excel,
		"sseChat":  c.SseChat,
		"dispatch": c.Dispatch,
		"vector":   c.Vector,
		"account":  c.Account,
		"faq":      c.FAQ,
		"aiCanvas": c.AiCanvas,
	}

	// 读取默认表格配置文件
	if _, err := toml.DecodeFile(filepath.Join(configDir, "excel.toml"), configFiles["excel"]); err != nil {
		log.Fatalf("读取配置文件 %s 异常 ---> %#v", "excel.toml", err)
	}
	// 根据run mode获取必须加载文件列表
	var fileList []string
	if c.RunMode == "" {
		fileList = []string{"agent", "sseChat", "dispatch", "vector", "account", "faq", "aiCanvas"}
	} else {
		fileList = Config.Excel.GetConfigNameList()
	}
	// 读取配置文件
	for _, name := range fileList {
		if _, err := toml.DecodeFile(filepath.Join(configDir, name+".toml"), configFiles[name]); err != nil {
			log.Fatalf("读取配置文件 %s 异常 ---> %#v", name+".toml", err)
		}
		// 读取账号信息
		if name == "account" {
			if err := Config.Account.getAccountByNetWork(); err != nil && slices.Contains([]string{"sseChat", "disPatch", "aiCanvas"}, Config.RunMode) {
				log.Fatalf("获取账号信息异常 ---> %#v", err)
			}
		} else if name == "aiCanvas" {
			if err := Config.AiCanvas.getWorkflowInfo(); err != nil {
				log.Fatalf("获取工作流信息异常 ---> %#v", err)
			}
		}
	}
}

// agent 智能体配置
type agent struct {
	Address             string           `toml:"address"`
	ApiKey              string           `toml:"api_key"`
	ModeType            string           `toml:"model"`
	Stream              bool             `toml:"stream"`
	TopK                float64          `toml:"top_k"`
	Temperature         float64          `toml:"temperature"`
	MaxTokens           int              `toml:"max_tokens"`
	DefaultSystemPrompt string           `toml:"default_system_prompt"`
	Tools               map[string][]any `toml:"tools"`
}

func (a *agent) CustomResponse(apiName string) string {
	// 根据apiName查找对应的响应
	if tool, ok := a.Tools[apiName]; ok {
		if len(tool) != 0 {
			// 随机返回一条响应
			rand.New(rand.NewSource(time.Now().UnixNano()))
			response := tool[rand.Intn(len(tool))]
			// map to string
			result, _ := json.Marshal(response)
			return string(result)
		}
	}
	return ""
}

// requestConfig 默认请求配置，请求头、请求体、地址。。。
type requestConfig struct {
	Address   string            `toml:"address,omitempty"`
	Header    map[string]string `toml:"Header"`
	Params    map[string]string `toml:"params"`
	Body      map[string]any    `toml:"Body"`
	TopString []string          `toml:"topString"`
}

// GetBody 获取请求体
func (r *requestConfig) GetBody() map[string]any {
	// 复制body并返回
	result := make(map[string]any)
	for k, v := range r.Body {
		result[k] = v
	}
	return result
}

// vector 向量配置
type vector struct {
	Embedding *requestConfig `toml:"embedding"`
	KmExt     *requestConfig `toml:"kmExt"`
}

// excel 表格相关配置
type excel struct {
	Header        map[string]excelRunModeHeader `toml:"header"`
	HeaderMapping map[string]string             `toml:"header_mapping"`
	Style         struct {
		FontName string             `toml:"fontName"`
		Width    map[string]float64 `toml:"width"`
	} `toml:"style"`
}

type excelRunModeHeader struct {
	Title          []string `toml:"title"`
	MustReadConfig []string `toml:"must_read_config"`
}

// GetExcelHeader 获取表头
func (e *excel) GetExcelHeader() []string {
	if h, ok := e.Header[Config.RunMode]; ok && len(h.Title) > 0 {
		return h.Title
	} else {
		panic("未找到对应的表头")
	}
}

func (e *excel) GetConfigNameList() []string {
	if h, ok := e.Header[Config.RunMode]; ok {
		return h.MustReadConfig
	} else {
		panic("未找到对应的表头")
	}
}

// UpdateExcelHeader 更新表头
func (e *excel) UpdateExcelHeader(h []string) []string {
	var result []string
	for _, col := range h {
		if _col, ok := e.HeaderMapping[col]; ok {
			col = _col
		}
		result = append(result, col)
	}
	return result
}

// TopN 获取TopN
func (e *excel) TopN() []int {
	var result []int
	for _, h := range e.GetExcelHeader() {
		if strings.HasPrefix(h, "命中原子名称_TOP") || strings.HasPrefix(h, "准确率_TOP") {
			h = strings.TrimPrefix(h, "命中原子名称_TOP")
			h = strings.TrimPrefix(h, "准确率_TOP")
			index, err := strconv.Atoi(h)
			if err != nil || index <= 0 {
				fmt.Println("请确认配置文件表头是否规范！")
				panic(err)
			}
			if !slices.Contains(result, index) {
				result = append(result, index)
			}
		}
	}
	sort.Ints(result)
	return result
}

// account 账号配置
type account struct {
	Account      map[string][]string `toml:"account"`
	ProvinceList map[string]string   `toml:"provinceList"`
	CreatedAt    time.Time           `toml:"creat_authcode_date"`
}

// GetProvinceCode 获取省份代码
func (a *account) GetProvinceCode(province string) (string, error) {
	// 检查输入字符串是否为空，如果为空则返回错误。
	if province == "" {
		return "", fmt.Errorf("未找到对应的省份代码")
	} else if province == "全国" || province == "000" {
		// 获取随机省份
		return a.GetRandomProvince(), nil
	}
	// 如果输入是数字，则直接返回该数字作为省份代码。
	if isNumeric(province) {
		return province, nil
	}
	// 尝试从省份列表中获取对应的省份代码。
	code, ok := a.ProvinceList[province]
	// 如果未找到对应的省份代码，则返回错误。
	if !ok {
		return "", fmt.Errorf("未找到%s对应的省份代码", province)
	}
	// 找到对应的省份代码，返回该代码。
	return code, nil
}

// GetAccount 获取账号。省份, 手机号, 鉴权码
func (a *account) GetAccount(province string) (string, string, string, error) {
	if a.Account == nil {
		log.Fatalf("请先初始化账号信息")
	}
	// 获取省份代码，如果省份名称无效，则返回错误。
	provinceCode, err := a.GetProvinceCode(province)
	if err != nil {
		return "", "", "", err
	}

	// 尝试从配置中获取对应省份的账号信息。
	accountList, ok := a.Account[provinceCode]
	if !ok {
		// 如果未找到对应省份的账号信息，则返回错误。
		return "", "", "", fmt.Errorf("未找到%s对应省份的账号", province)
	}

	// 初始化随机数
	randomIndex := rand.Intn(len(accountList))
	accountInfo := accountList[randomIndex]

	accountInfoList := strings.Split(accountInfo, "|")

	// 根据随机索引返回手机号和鉴权码。
	return provinceCode, accountInfoList[1], accountInfoList[0], nil
}

// GetRandomProvince 获取随机省份
func (a *account) GetRandomProvince() string {
	var provinceList []string
	for provinceCode, _ := range a.Account {
		provinceList = append(provinceList, provinceCode)
	}
	// 初始化随机数
	randomIndex := rand.Intn(len(provinceList))
	return provinceList[randomIndex]
}

// getAccountByNetWork 获取账号信息
func (a *account) getAccountByNetWork() error {
	// 判断账号信息是否为当天生成
	if time.Now().Format("2006-01-02") == a.CreatedAt.Format("2006-01-02") {
		return nil
	}

	// 获取新数据
	newAccount, err := middle.GetAccountByNetWork()
	if err != nil {
		return err
	}

	// 更新账号信息
	a.Account = newAccount

	// 更新时间
	a.CreatedAt = time.Now()

	// 写入配置文件
	file, _ := os.OpenFile(filepath.Join(configDir, "account.toml"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	defer file.Close()
	err = toml.NewEncoder(file).Encode(a)
	if err != nil {
		return err
	}
	return nil
}

// FaQConfig faq配置
type FaQConfig struct {
	requestConfig
	Category map[string]map[string]string `toml:"category"`
}

// GetCategory 获取分类
func (f *FaQConfig) GetCategory(province string, category ...string) []string {
	var categoryList []string
	for _, categoryName := range category {
		if categoryMap, ok := f.Category[categoryName]; ok {
			if categoryId, ok := categoryMap[province]; ok {
				categoryList = append(categoryList, categoryId)
			}
			if categoryId, ok := categoryMap["全国"]; ok {
				categoryList = append(categoryList, categoryId)
			}
		}
	}

	return categoryList
}

// aiCanvasConfig 画布服务配置
type aiCanvasConfig struct {
	Scheme      string              `toml:"scheme"`
	Host        string              `toml:"host"`
	Port        int64               `toml:"port"`
	Path        string              `toml:"path"`
	DebugPath   string              `toml:"debugPath"`
	Debug       bool                `toml:"debug"`
	Cookie      map[string]string   `toml:"Cookie"`
	Header      map[string]string   `toml:"Header"`
	Body        map[string]string   `toml:"Body"`
	WorkFlowMap map[string][]string `toml:"workFlowMap"`
	CreatedAt   time.Time           `toml:"creat_date"`
}

func (aic *aiCanvasConfig) GetBody() map[string]string {
	return maps.Clone(aic.Body)
}

func (aic *aiCanvasConfig) UpdateBody(d map[string]string) bool {
	if d == nil {
		return true
	}
	maps.Copy(aic.Body, d)
	return true
}
func (aic *aiCanvasConfig) GetHeader() map[string]string {
	return maps.Clone(aic.Header)
}

// FindCanvasInfo 获取画布信息
func (aic *aiCanvasConfig) FindCanvasInfo(intentName string) (
	appId string, appSecret string,
	bodyId string, startId string, versionId string, err error,
) {
	if aic.WorkFlowMap == nil {
		log.Fatalf("请先初始化画布服务信息")
	}
	if workflowInfo, ok := aic.WorkFlowMap[intentName]; ok {
		return workflowInfo[0], workflowInfo[1], workflowInfo[2], workflowInfo[3], workflowInfo[4], nil
	} else {
		return "", "", "", "", "", fmt.Errorf("未找到%s对应的画布信息", intentName)
	}
}

// getAccountByNetWork 获取账号信息
func (aic *aiCanvasConfig) getWorkflowInfo() error {
	// 判断账号信息是否为当天生成
	if time.Now().Format("2006-01-02") == aic.CreatedAt.Format("2006-01-02") && aic.WorkFlowMap != nil {
		return nil
	}

	// 获取新数据
	newWorkflowInfo, err := middle.GetWorkflowInfo()
	if err != nil {
		return err
	}
	aic.WorkFlowMap = newWorkflowInfo

	// 更新时间
	aic.CreatedAt = time.Now()

	// 写入配置文件
	file, _ := os.OpenFile(filepath.Join(configDir, "aiCanvas.toml"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	defer file.Close()
	err = toml.NewEncoder(file).Encode(aic)
	if err != nil {
		return err
	}
	return nil
}
